// Dynamic symbol table management

#include <extend.h>

typedef struct
{
   PDYNSYM pDynSym;
} DYNITEM, * PDYNITEM;

void Debug( LPSTR );

PSYMBOL  NewSymbol( LPSTR szName );
PDYNSYM  FindDynSym( LPSTR szName );

LPVOID   pOVMSymbols = 0;
PDYNITEM pDynItems = 0;
WORD     wDynSymbols = 0, wClosestDynSym = 0;

//----------------------------------------------------------------------------//

void LogSymbols( void )
{
   WORD w;

   LogFile( "info.log", "" );
   LogFile( "info.log", "Dynamic Symbols" );
   LogFile( "info.log", "===============\n" );

   for( w = 0; w < wDynSymbols; w++ )
      LogFile( "info.log", pDynItems[ w ].pDynSym->pSymbol->szName );
}

//----------------------------------------------------------------------------//

PDYNSYM NewDynSym( PSYMBOL pSymbol )    // creates a new dynamic symbol
{
   PDYNSYM pDynSym = FindDynSym( pSymbol->szName );
   WORD w;
   BYTE buffer[ 10 ];

   if( pDynSym )
   {
      if( ( ! pDynSym->pFuncPtr ) && pSymbol->pVoid )  // The DynSym existed
         pDynSym->pFuncPtr = pSymbol->pVoid;   // but had no function ptr assigned

      pSymbol->pVoid = pDynSym;               // place a pointer to DynSym

      return pDynSym;
   }

   if( ! wDynSymbols )
      pDynSym = pDynItems[ 0 ].pDynSym;
   else
   {
      // _str( wClosestDynSym, buffer, 10 );
      // MsgInfo( buffer, "wClosestDynSym" );
      // _str( wDynSymbols, buffer, 10 );
      // MsgInfo( buffer, "wDynSymbols" );

      // _vmUnLock( pOVMSymbols );

      _vmRealloc( pOVMSymbols, _vmSize( pOVMSymbols ) + sizeof( DYNITEM ) );
      pDynItems = _vmLock( pOVMSymbols );

      if( wClosestDynSym <= wDynSymbols )
      {
         for( w = 0; w < ( wDynSymbols - wClosestDynSym ); w++ )
         {
            _bcopy( &pDynItems[ wDynSymbols - w ],
                    &pDynItems[ wDynSymbols - w - 1 ], sizeof( DYNITEM ) );

            // MsgInfo( "copiando desde", pDynItems[ wDynSymbols - w - 1 ].pSymbol->szName );
         }
      }
      pDynSym = _vmLock( _vmAlloc( sizeof( DYNSYM ) ) );
      pDynItems[ wClosestDynSym ].pDynSym = pDynSym;
   }

   wDynSymbols++;
   pDynSym->pSymbol = pSymbol;

   if( pDynSym->pFuncPtr != pSymbol->pVoid )  // it contains a function pointer
      pDynSym->pFuncPtr = pSymbol->pVoid;     // place the function at DynSym

   pSymbol->pVoid = pDynSym;               // place a pointer to DynSym

   return pDynSym;
}

//----------------------------------------------------------------------------//

PDYNSYM _GetDynSym( LPSTR szName )  // finds and creates a symbol if not found
{
   PDYNSYM pDynSym;

   _strupper( szName, szName );

   if( _strlen( szName ) > 10 )
      szName[ 10 ] = 0;

   if( ! ( pDynSym = FindDynSym( szName ) ) )
   {
      Debug( "NewDynSym" );
      Debug( szName );
      return NewDynSym( NewSymbol( szName ) );
   }
   else
      return pDynSym;
}

//----------------------------------------------------------------------------//

PDYNSYM FindDynSym( LPSTR szName )
{
   WORD wFirst = 0, wLast = wDynSymbols, wMiddle = wLast / 2;
   BYTE buffer[ 10 ];

   if( ! pOVMSymbols )
   {
      pOVMSymbols = _vmAlloc( sizeof( DYNITEM ) );
      pDynItems   = _vmLock( pOVMSymbols );
      pDynItems[ 0 ].pDynSym = _vmLock( _vmAlloc( sizeof( DYNSYM ) ) );
      return 0;
   }
   else
   {
      wClosestDynSym = wMiddle;

      // MsgInfo( "chequeando", szName );

      while( wFirst < wLast )
      {
         // _str( wDynSymbols, buffer, 10 );
         // MsgInfo( buffer, "wDynSymbols" );
         // _str( wMiddle, buffer, 10 );
         // MsgInfo( buffer, "wMiddle" );

         switch( _strgreater( pDynItems[ wMiddle ].pDynSym->pSymbol->szName, szName ) )
         {
            case 0:  // they are equals
                 // MsgInfo( "they are equals", "ok" );
                 return pDynItems[ wMiddle ].pDynSym;
                 break;

            case 1:  // pMiddle is greater
                 // MsgInfo( pDynItems[ wMiddle ].pSymbol->szName, "greater" );
                 wLast = wMiddle;
                 wClosestDynSym = wMiddle;
                 break;

            case 2:  // szName is greater
                 // MsgInfo( szName, "greater" );
                 wFirst = wMiddle + 1;
                 wClosestDynSym = wFirst;
                 break;
         }
         wMiddle = wFirst + ( ( wLast - wFirst ) / 2 );
      }
   }
   return 0;
}

//----------------------------------------------------------------------------//

CLIPPER DYNSYMNAME()
{
   _retc( pDynItems[ _parnl( 1 ) - 1 ].pDynSym->pSymbol->szName );
}

//----------------------------------------------------------------------------//

CLIPPER DYNSYMBOLS()
{
   _retnl( wDynSymbols );
}

//----------------------------------------------------------------------------//

CLIPPER GETDYNSYM()
{
   _retnl( ( LONG ) _GetDynSym( _parc( 1 ) ) );
}

//----------------------------------------------------------------------------//
